#include "DAEMatrix33.h"

DAEMatrix33::DAEMatrix33(void)
{
}

DAEMatrix33::DAEMatrix33(DAEFloat3 A)
{
	SetRow(0, A.x * A.x, A.y * A.x, A.z * A.x);
	SetRow(1, A.x * A.y, A.y * A.y, A.z * A.y);
	SetRow(2, A.x * A.z, A.y * A.z, A.z * A.z);
}

DAEMatrix33::~DAEMatrix33(void)
{
}

void DAEMatrix33::SetCell(int row, int column, float value)
{
	m_RMData[row*3+column]=value;
}

float DAEMatrix33::GetCell(int row, int column) const
{
	return m_RMData[row*3+column];
}

void DAEMatrix33::SetRow(int row, DAEFloat3& value)
{
	m_RMData[row*3]   = value.x;
	m_RMData[row*3+1] = value.y;
	m_RMData[row*3+2] = value.z;
}

void DAEMatrix33::SetRow(int row, float a1, float a2, float a3)
{
	m_RMData[row*3]   = a1;
	m_RMData[row*3+1] = a2;
	m_RMData[row*3+2] = a3;
}

void DAEMatrix33::SetColumn(int column, DAEFloat3& value)
{
	m_RMData[column]      = value.x;
	m_RMData[3 + column]  = value.y;
	m_RMData[6 + column]  = value.z;
}
	
void DAEMatrix33::SetColumn(int column, float a1, float a2, float a3)
{
	m_RMData[column]      = a1;
	m_RMData[3 + column]  = a2;
	m_RMData[6 + column]  = a3;
}

void DAEMatrix33::GetRow(int row, DAEFloat3& value) const
{
	value.x = m_RMData[row*3];
	value.y = m_RMData[row*3+1];
	value.z = m_RMData[row*3+2];
}
	
void DAEMatrix33::GetColumn(int column, DAEFloat3& value) const
{
	value.x = m_RMData[column];
	value.y = m_RMData[3+column];
	value.z = m_RMData[6+column];
}


void DAEMatrix33::SetAsIdentity()
{
	this->SetRow(0,1,0,0);
	this->SetRow(1,0,1,0);
	this->SetRow(2,0,0,1);
}

void DAEMatrix33::Inverse(DAEMatrix33& result)
{
	float det = Determinant();
	// | a11 a12 a13 |-1             |   a33a22-a32a23  -(a33a12-a32a13)   a23a12-a22a13  |
	// | a21 a22 a23 |    =  1/DET * | -(a33a21-a31a23)   a33a11-a31a13  -(a23a11-a21a13) |
	// | a31 a32 a33 |               |   a32a21-a31a22  -(a32a11-a31a12)   a22a11-a21a12  |
	float a11 = GetCell(0,0);
	float a12 = GetCell(0,1);
	float a13 = GetCell(0,2);

	float a21 = GetCell(1,0);
	float a22 = GetCell(1,1);
	float a23 = GetCell(1,2);

	float a31 = GetCell(2,0);
	float a32 = GetCell(2,1);
	float a33 = GetCell(2,2);

	result.SetCell(0,0, (a33*a22 - a32*a23)/det);
	result.SetCell(0,1, -(a33*a12 -a32*a13)/det);
	result.SetCell(0,2,(a23*a12-a22*a13)/det);

	result.SetCell(1,0, -(a33*a21-a31*a23)/det);
	result.SetCell(1,1, (a33*a11-a31*a13)/det);
	result.SetCell(1,2, -(a23*a11-a21*a13)/det);

	result.SetCell(2,0, (a32*a21-a31*a22)/det); 
	result.SetCell(2,1, -(a32*a11-a31*a12)/det);
	result.SetCell(2,2,  (a22*a11-a21*a12) /det);
}

float DAEMatrix33::Determinant() const
{
	return m_RMData[0]*(m_RMData[4]*m_RMData[8]-m_RMData[5]*m_RMData[7])
		-m_RMData[1]*(m_RMData[3]*m_RMData[8]-m_RMData[5]*m_RMData[6])
		+m_RMData[2]*(m_RMData[3]*m_RMData[7]-m_RMData[4]*m_RMData[6]);
}

void DAEMatrix33::TransformVector(DAEFloat3& vOut, DAEFloat3& vToTransform) const
{
	float x = vToTransform.x * GetCell(0,0) + vToTransform.y * GetCell(1,0) + vToTransform.z * GetCell(2,0);
	float y = vToTransform.x * GetCell(0,1) + vToTransform.y * GetCell(1,1) + vToTransform.z * GetCell(2,1);
	float z = vToTransform.x * GetCell(0,2) + vToTransform.y * GetCell(1,2) + vToTransform.z * GetCell(2,2);
	vOut.SetValues(x,y,z);

}